#
# Testing the bug repository
#

import os, sys
from Testing import ZopeTestCase
from pprint import pprint
from AccessControl.SecurityManagement import newSecurityManager


# local imports
from Products import DDBug
from Products.DDBug.interfaces import IBugRepository, IBug
from Products.DDBug import permissions

# some global vars
_standard_permissions = ZopeTestCase._standard_permissions

# the testcases themselves
class TestRepo(ZopeTestCase.ZopeTestCase):
    def afterSetUp(self):
        '''Add repository to default fixture'''
        self.folder._addRole('Customer')
        self.folder.acl_users._addUser('programmmer', 'secret', 'secret', ('Manager',), ())
        self.folder.acl_users._addUser('customer', 'secret2', 'secret2', ('Customer',), ())
        dispatcher = self.folder.manage_addProduct['DDBug']
        dispatcher.manage_addBugRepository('repo')
        self.repo = self.folder['repo']

    def afterClear(self):
        '''Clean up after myself'''
        try: del self.repo
        except AttributeError: pass

    # Test fixture ##################################################

    def test_creation(self):
        #'''Test bug repository creation'''
        self.failUnless(hasattr(self.folder, 'repo'),
                        "repository wasn't created")
        self.failUnless(IBugRepository.isImplementedBy(self.repo),
                        "repository doesn't implement IBugRepository")

    def test_meta_type(self):
        self.failUnlessEqual(self.repo.meta_type, "DDBug Repository", "Wrong meta_type for the repository")

    # template tests
    def test_manage_addBugForm(self):
        htmlResult = self.repo.manage_addBugForm()

    def test_index_html(self):
        # first with no bugs
        htmlResult = self.repo.index_html()
        # now with a bug
        self.setPermissions([permissions.ADD_BUG])
        self.repo.manage_addBug()
        htmlResult = self.repo.index_html()

    def test_index2_html(self):
        # first with no bugs
        htmlResult = self.repo.index2_html()
        # now with a bug
        self.setPermissions([permissions.ADD_BUG])
        self.repo.manage_addBug()
        htmlResult = self.repo.index2_html()

    def test_index3_html(self):
        # first with no bugs
        htmlResult = self.repo.index3_html()
        # now with a bug
        self.setPermissions([permissions.ADD_BUG])
        self.repo.manage_addBug()
        htmlResult = self.repo.index3_html()

    def test_report(self):
        # first with no bugs
        htmlResult = self.repo.report()
        # now with a bug
        self.setPermissions([permissions.ADD_BUG])
        self.repo.manage_addBug()
        htmlResult = self.repo.report()

    def test_MasterBug(self):
        self.failUnlessEqual(self.repo.MasterBug.meta_type, "DDBug Bug",
                             "Wrong meta_type for the MasterBug")
        self.failUnless(IBug.isImplementedBy(self.repo.MasterBug),
                        "MasterBug doesn't implement IBug")

    def test_bugValues(self):
        self.setPermissions([permissions.ADD_BUG])
        self.repo.newBug()
        self.failUnlessEqual(len(self.repo.bugValues()), 1, 'len of self.repo.bugValues() should 1 but got %s' % len(self.repo.bugValues()))
        self.failUnlessEqual(len(self.repo.bugValues(open=1)), 1, 'len of self.repo.bugValues() should 1 but got %s' % len(self.repo.bugValues()))
        self.failUnlessEqual(len(self.repo.bugValues(open=0)), 0, 'len of self.repo.bugValues() should 0 but got %s' % len(self.repo.bugValues()))
        
    def test_bugIds_nobugs(self):
        # only bugIds for the time being

        # let's add some random object in the bugrepo, say, a folder
        # it shouldn't show up on the bugId list
        self.repo.manage_addFolder(id="aFolder")
        bugIds = self.repo.bugIds()
        for bugId in bugIds:
            # it should be iterable, so the "for" should not fail
            # but we don't want any interations either
            # since the list is supposed to be empty
            self.fail("self.repo.bugIds() already has items but shouldn't")

    def test_bugIds_one_bug(self):
        self.setPermissions([permissions.ADD_BUG])
        bug0 = self.repo.newBug()
        bugIds = self.repo.bugIds()
        self.failUnlessEqual(bug0.getId(), bugIds[0],
                             "inserted bug id didn't show up in .bugIds")

    def test_getNextId_nobugs(self):
        bugId = '0001'
        # with no bugs, it should return something like "0000"
        self.failUnlessEqual(bugId, self.repo.getNextId(),
                             "Wrong generated bug Id for empty repository")
        # even when called twice
        self.failUnlessEqual(bugId, self.repo.getNextId(),
                             "Wrong generated bug Id for empty repository "
                             "when .getNextId() is called twice")
        self.repo.manage_addFolder(id="aFolder")
        self.failUnlessEqual(bugId, self.repo.getNextId(),
                             "Wrong generated bug Id for repository with no"
                             "bugs when there's something else in it")

    def test_getNextId_one_bug(self):
        # now let's add a bug
        self.setPermissions([permissions.ADD_BUG])
        self.repo.newBug()
        # next bugId should be something like "0001"
        bugId = '0002'
        self.failUnlessEqual(bugId, self.repo.getNextId(),
                             "Wrong generated bug Id for repository "
                             "with one bug")
        # even when called twice
        self.failUnlessEqual(bugId, self.repo.getNextId(),
                             "Wrong generated bug Id for repository "
                             "with one bug, when .getNextId() is called twice")

    def test_newBug(self):
        #'''Test bug creation'''
        self.setPermissions([permissions.ADD_BUG])
        bug0 = self.repo.newBug()
        # let's check the which id the bug got
        bugIdMask = self.repo.bugIdMask
        bug0id = bugIdMask % 1 # something like "0001"
        self.failUnlessEqual(bug0id, bug0.getId(),
                             "first bug id should be '%s' but is '%s'" %
                             (bug0id, bug0.getId()))
        self.failUnless(hasattr(self.repo, bug0id),
                        "first bug didn't show up in the repository")
        # now let's try to fetch it from the repository itself
        bug0r = self.repo[bug0id]
        self.failUnlessEqual(bug0, bug0r,
                             "repo.newBug() and repo[%s] don't match" % bug0id)
        self.failUnlessEqual(bug0.meta_type, "DDBug Bug",
                             "Wrong meta_type for Bug")
        # now let's try a second bug
        bug1title = "second bug has title"
        bug1 = self.repo.newBug()
        bug1id = bugIdMask % 2
        self.failUnlessEqual(bug1id, bug1.getId(),
                             "second bug id should be '%s' but is '%s'" %
                             (bug1id, bug1.getId()))

    def no_test_manage_addBug(self):
        # we will need the right permission for this one
        self.setPermissions([permissions.ADD_BUG])
        req = self.repo.REQUEST
        title = "A certain bug title"
        req.form['title'] = title
        self.repo.manage_addBug(req)
        bugIdMask = self.repo.bugIdMask
        bugId = bugIdMask % 0
        bug = self.repo[bugId]
        self.failUnlessEqual(title, bug.title,
                             "bug title should be '%s' but is '%s'" %
                             (title, bug.title))
        

    def test_listByPriority_nobugs(self):
        bugList = self.repo.listByProperty('priority', value="1")
        for bug in bugList:
            # it should be iterable, so the "for" should not raise
            # an exception but we don't want any iterations either
            # since the list is supposed to be empty
            self.fail(".repo.listByPriority() already has items but no bug "
                      "was added")

    def test_listByPriority_len(self):
        # now let's test with one bug
        self.setPermissions([permissions.ADD_BUG])
        bug = self.repo.newBug()
        bug.manage_changeProperties(priority="1")
        bugList = self.repo.listByProperty('priority', value="1")
        self.failUnless(len(bugList) == 1,
                        ".listByPriority() didn't return the bug we added")

    def test_listBugs_priority(self):
        self.setPermissions([permissions.ADD_BUG])
        bug = self.repo.newBug()
        # let's change the Priority
        bug.manage_changeProperties(priority="2")
        bugList = self.repo.listByProperty('priority', value="1")
        self.failUnless(len(bugList) == 0,
                        ".listByPriority(priority='1') listed bug with priority='2'")

    def test_dumpBugsByPriority(self):
        self.setPermissions([permissions.ADD_BUG])
        for p in [str(x) for x in range(1,6) if x != 2]:
            bug = self.repo.newBug()
            bug.manage_editBug(title="bug "+p , priority=p)
            if p == "4":
                bug.manage_editBug(status = "DISCARDED")
        bug = self.repo.newBug()
        bug.manage_editBug(title="bug 3b", priority="3")
        dump = self.repo.dumpBugsByPriority(open=1)
        assert len(dump) == 3
        assert dump[0]['priority'] == "1"
        assert len(dump[0]['bugs']) == 1
        assert dump[1]['priority'] == "3"
        assert len(dump[1]['bugs']) == 2
        assert dump[2]['priority'] == "5"
        assert len(dump[2]['bugs']) == 1
        dump = self.repo.dumpBugsByPriority(open=0)
        assert len(dump) == 1
        assert dump[0]['priority'] == "4"
        assert len(dump[0]['bugs']) == 1

    def test_dumpBugsByStatus(self):
        self.setPermissions([permissions.ADD_BUG])
        count = 0
        for s in self.repo.MasterBug.optionsForStatus():
            bug = self.repo.newBug()
            bug.manage_editBug(priority=str(count%5+1), status=s)
            count += 1
        bug = self.repo.newBug()
        bug.manage_editBug(priority="3", status='RE-SENT')
        dump_open = self.repo.dumpBugsByStatus(open=1)
        dump_closed = self.repo.dumpBugsByStatus(open=0)
        self.assertEquals(len(dump_open), 7)
        assert dump_open[0]['status'] == "New"
        assert len(dump_open[0]['bugs']) == 1
        assert dump_open[1]['status'] == "Analisys"
        assert len(dump_open[1]['bugs']) == 1
        assert dump_open[3]['status'] == "Re-Sent"
        assert len(dump_open[3]['bugs']) == 2
        assert dump_open[-1]['status'] == "Fixed"
        assert len(dump_open[-1]['bugs']) == 1
        
        assert len(dump_closed) == 4
        assert dump_closed[0]['status'] == "Approved"
        assert len(dump_closed[0]['bugs']) == 1
        assert dump_closed[-1]['status'] == "Postponed"
        assert len(dump_closed[-1]['bugs']) == 1        

    def test_getRepository(self):
        self.assertEquals(self.repo, self.repo.getRepository(),
                          "getRepository returned wrong object.")

    def test_dumpBugsBySeverities(self):
        self.setPermissions([permissions.ADD_BUG])
        for s in self.repo.MasterBug.optionsForSeverity():
            bug = self.repo.newBug()
            bug.manage_editBug(severity=s)
        bug = self.repo.newBug()
        bug.manage_editBug(severity='IMPROVEMENT')
        
        dump_open   = self.repo.dumpBugsBySeverities(open=1)
        self.assertEquals(len(dump_open), 5)
        assert dump_open[0]['severity'] == "Critical"
        assert len(dump_open[0]['bugs']) == 1
        assert dump_open[1]['severity'] == "Unavoidable"
        assert len(dump_open[1]['bugs']) == 1
        assert dump_open[3]['severity'] == "Cosmetic"
        assert len(dump_open[3]['bugs']) == 1
        assert dump_open[-1]['severity'] == "Improvement"
        assert len(dump_open[-1]['bugs']) == 2

    def test_getAuthenticatedUser(self):
        testName='customer'
        # Log in as the testUser
        uf = self.folder.acl_users
        testUser = uf.getUserById(testName).__of__(uf)
        newSecurityManager(None, testUser)
        loggedName = self.repo.getAuthenticatedUser()
        assert str(loggedName) == str(testName)
        
    def test_getTotalOfEstimatedTimeToFix(self):
        self.setPermissions([permissions.ADD_BUG])        
        for i in range(1,5):
            bug = self.repo.manage_addBug(estimated_time_to_fix=i)
        self.failUnlessEqual(0, self.repo.getTotalOfEstimatedTimeToFix(open=0),
                            'the total shold be 0 but got %s' % 
                             self.repo.getTotalOfEstimatedTimeToFix(open=0))

        self.failUnlessEqual(10, self.repo.getTotalOfEstimatedTimeToFix(open=1),
                            'the total shold be 10 but got %s' % 
                             self.repo.getTotalOfEstimatedTimeToFix(open=1))
        
    def test_getTotalOfactualTimeToFix(self):
        self.setPermissions([permissions.ADD_BUG])        
        for i in range(1,5):
            bug = self.repo.manage_addBug(actual_time_to_fix=i)
        self.failUnlessEqual(10, self.repo.getTotalOfactualTimeToFix(open=1),
                            'the total shold be 10 but got %s' % 
                            self.repo.getTotalOfactualTimeToFix(open=1))

if __name__ == '__main__':
    framework(descriptions=1, verbosity=2)
else:
    import unittest
    def test_suite():
        suite = unittest.TestSuite()
        suite.addTest(unittest.makeSuite(TestRepo))
        return suite

